#include "backdrop_editor_scroll.h"
#include "backdrop_scroll.h"
#include "backdrop_layer.h"
#include "decal.h"


#include "graphics/graphics_util.h"
#include "util/common_macros.h"
#include "util/mmgr.h"

#include <math.h>
namespace backdrop
{

class DecalScrollBrush : public BackdropBrush
{
public:
	DecalScrollBrush(BackdropEditor* pEditor, const std::string& Name) : BackdropBrush(pEditor, Name) {
		m_Sprite.Create(Name);
	}

	virtual ~DecalScrollBrush() {
	}

	virtual void Tick(float dt) {
		if (m_Sprite.IsValid()) m_Sprite.Tick(dt);
	}

	virtual void Render() {
		if (m_Sprite.IsValid()) m_Sprite.Render();
	}

	virtual void FollowMouse(const math::Vec2& Pos) {
		m_Pos = Pos - (0.5f * m_Sprite.m_Size);
		if (m_Sprite.IsValid()) m_Sprite.Setup(m_Pos - m_pEditor->GetOffset(), m_Sprite.m_Size);
	}

	virtual void Place() {
		std::string SpriteName = m_Name;
		if (!m_Type.empty()) SpriteName += "[" + m_Type + "]";
		if (Decal* pDecal = m_pEditor->GetBackdrop()->CreateDecalSprite(SpriteName, m_Pos))
		{
			if (BackdropLayer* pLayer = ((BackdropEditorScroll*)m_pEditor)->GetCurrentLayerPtr()) {
				pLayer->AddDecalSprite(pDecal);
				pDecal->SetPos(m_Pos - m_pEditor->GetOffset() + (pLayer->GetParallax() * m_pEditor->GetBackdrop()->GetOffset()));
			} else
				m_pEditor->GetBackdrop()->AddDecalSprite(pDecal);
		}
	}

	virtual void Rotate(const int& Dir = 0) {
	}

protected:
	ui::UISprite	m_Sprite;
};



BackdropEditorScroll::BackdropEditorScroll(BackdropScroll* pBackdrop) : BackdropEditor(pBackdrop),
	m_CurrentLayer(-1),
	m_LayerHighlightInit(false)
{
}

BackdropEditorScroll::~BackdropEditorScroll()
{
}

bool BackdropEditorScroll::GetCurrentLayer(int* piLayer, bool* pbForeground)
{
	if (!AllowLayerEdit()) return false;
	if (m_CurrentLayer < 0) return false;
	if (m_CurrentLayer == MaxLayers()) return false;

	bool Foreground = (m_CurrentLayer > MaxLayers());
	int Layer = Foreground ? (m_CurrentLayer - MaxLayers() - 1) : m_CurrentLayer;

	if (Layer >= (int)GetScrollBackdrop()->GetLayerC(!Foreground)) {
		if (BackdropLayer* pLayer = GetScrollBackdrop()->AddLayer(Layer, 1.0f, !Foreground))
			pLayer->ResetLayer();
	}

	if (piLayer) *piLayer = Layer;
	if (pbForeground) *pbForeground = Foreground;
	return true;
}

BackdropLayer* BackdropEditorScroll::GetCurrentLayerPtr()
{
	bool Foreground;
	int Layer;

	if (!GetCurrentLayer(&Layer, &Foreground))
		return NULL;

	return GetScrollBackdrop()->GetLayer(Layer, !Foreground);
}

void BackdropEditorScroll::Tick(float dt)
{
	BackdropEditor::Tick(dt);

	// do edge scrolling
	math::Vec2 MPos = GET_MOUSE().GetPos();
	math::Vec2 Scroll(0.0f, 0.0f);
	float Edge = GetScrollEdge();

	if (MPos.x < Edge)
		Scroll.x = -GetScrollSpeed();
	else if (MPos.x > (1.0f - Edge))
		Scroll.x = GetScrollSpeed();

	if (MPos.y < Edge)
		Scroll.y = -GetScrollSpeed();
	else if (MPos.y > (1.0f - Edge))
		Scroll.y = GetScrollSpeed();

	if (Scroll.MagSqr() > 0.0f)
	{
		Scroll *= dt;
		GetScrollBackdrop()->Scroll(Scroll);
	}
}

void BackdropEditorScroll::KeyPressed(input::Keyboard::KEY* pKey)
{
	input::Keyboard* pKB = &GET_KEYBOARD();
	bool bCtrl = pKB->IsCtrlDown();

	if (AllowLayerEdit() && (m_CurrentLayer >= 0))
	{
		bool bRet = false;

		switch (pKey->KeyID)
		{
		case KEY_INSERT:
			ToggleUVScroll();
			bRet = true;
			break;
		case KEY_DELETE:
			DeleteLayerBackground();
			bRet = true;
			break;
		case KEY_HOME:
			ChangeLayer(true);
			bRet = true;
			break;
		case KEY_END:
			ChangeLayer(false);
			bRet = true;
			break;
		case KEY_PRIOR:
			SetParallax(true);
			bRet = true;
			break;
		case KEY_NEXT:
			SetParallax(false);
			bRet = true;
			break;
		case KEY_LBRACKET:
			if (bCtrl) {
				MoveLayer(false);
				bRet = true;
			}
			break;
		case KEY_RBRACKET:
			if (bCtrl) {
				MoveLayer(true);
				bRet = true;
			}
			break;
		}

		if (bRet) {
			RefreshAltText();
			return;
		}
	}

	/*
	switch (pKey->KeyID)
	{
	default:
		BackdropEditor::KeyPressed(pKey);
		break;
	}
	*/
	BackdropEditor::KeyPressed(pKey);
}

void BackdropEditorScroll::SetDecalBrush(const std::string& Name, const std::string& Type)
{
	if (AllowLayerEdit())
	{
		AddStatusMsg("Decal selected");

		UTIL_SAFE_DELETE(m_pBrush);
		m_pBrush = new DecalScrollBrush(this, Name);
		m_pBrush->FollowMouse( GET_MOUSE().GetPos() + GetOffset() );

		if (Type.empty())
			m_pBrush->SetType(m_BrushType);
		else
			SetDecalBrushType(Type);
	}
	else
		BackdropEditor::SetDecalBrush(Name, Type);
}

void BackdropEditorScroll::ToggleUVScroll()
{
	if (BackdropLayer* pLayer = GetCurrentLayerPtr())
	{
		std::string Name = pLayer->GetName();
		float Parallax = pLayer->GetParallax();
		bool bUVScroll = !pLayer->IsUVScroll();

		pLayer->Create(Name, bUVScroll, Parallax);
		pLayer->ResetLayer();
	}
}

void BackdropEditorScroll::DeleteLayerBackground()
{
	if (BackdropLayer* pLayer = GetCurrentLayerPtr())
	{
		float Parallax = pLayer->GetParallax();
		bool bUVScroll = pLayer->IsUVScroll();

		pLayer->Create("", bUVScroll, Parallax);
		pLayer->ResetLayer();
	}
}

void BackdropEditorScroll::ChangeLayer(bool bIncrement)
{
	BackdropLayer* pLayer = NULL;

	if (bIncrement)
	{
		if (m_CurrentLayer < (2 * MaxLayers())) {
			if (m_LayerHighlightInit)
				pLayer = GetCurrentLayerPtr();
			m_CurrentLayer++;
		}
	}
	else
	{
		if (m_CurrentLayer) {
			if (m_LayerHighlightInit)
				pLayer = GetCurrentLayerPtr();
			m_CurrentLayer--;
		}
	}

	if (m_LayerHighlightInit)
	{
		// disable previous layer
		if (pLayer)
			pLayer->SetIsEnabled(false);

		// enable current layer
		if (pLayer = GetCurrentLayerPtr())
			pLayer->SetIsEnabled(true);
	}
}

void BackdropEditorScroll::SetParallax(bool bIncrement)
{
	if (BackdropLayer* pLayer = GetCurrentLayerPtr())
	{
		std::string Name = pLayer->GetName();
		float Parallax = pLayer->GetParallax();
		bool bUVScroll = pLayer->IsUVScroll();

		Parallax += bIncrement ? 0.05f : -0.05f;
		UTIL_CLAMP(Parallax, 0.0f, 1.0f);

		pLayer->Create(Name, bUVScroll, Parallax);
		pLayer->ResetLayer();
	}
}

void BackdropEditorScroll::MoveLayer(bool bForward)
{
	if (m_CurrentLayer == MaxLayers()) return;

	BackdropLayer* pLayer1 = NULL;
	BackdropLayer* pLayer2 = NULL;
	int CurrentLayer = m_CurrentLayer;

	bool Insert1, Insert2; // background or foreground
	int idx1, idx2; // insertion index

	if (bForward)
	{
		if (m_CurrentLayer == (MaxLayers() - 1))
		{
			pLayer1 = GetCurrentLayerPtr();
			m_CurrentLayer = MaxLayers() + 1;
			pLayer2 = GetCurrentLayerPtr();

			Insert1 = false;
			Insert2 = true;
			idx1 = 0;
			idx2 = -1;
		}
		else if (m_CurrentLayer < (2 * MaxLayers()))
		{
			pLayer1 = GetCurrentLayerPtr();
			m_CurrentLayer++;
			pLayer2 = GetCurrentLayerPtr();

			Insert1 = Insert2 = (CurrentLayer < MaxLayers()) ? true : false;
			idx1 = idx2 = (CurrentLayer < MaxLayers()) ? CurrentLayer : (CurrentLayer - MaxLayers() - 1);
		}
		else
			return;
	}
	else
	{
		if (m_CurrentLayer == (MaxLayers() + 1))
		{
			pLayer1 = GetCurrentLayerPtr();
			m_CurrentLayer = MaxLayers() - 1;
			pLayer2 = GetCurrentLayerPtr();

			Insert1 = true;
			Insert2 = false;
			idx1 = -1;
			idx2 = 0;
		}
		else if (m_CurrentLayer > 0)
		{
			m_CurrentLayer--;
			pLayer1 = GetCurrentLayerPtr();
			m_CurrentLayer++;
			pLayer2 = GetCurrentLayerPtr();
			m_CurrentLayer--;

			Insert1 = Insert2 = (m_CurrentLayer < MaxLayers()) ? true : false;
			idx1 = idx2 = (m_CurrentLayer < MaxLayers()) ? m_CurrentLayer : (m_CurrentLayer - MaxLayers() - 1);
		}
		else
			return;
	}

	if (!pLayer1 || !pLayer2) {
		m_CurrentLayer = CurrentLayer;
		return;
	}

	GetScrollBackdrop()->DeleteLayer(pLayer1, false);
	GetScrollBackdrop()->DeleteLayer(pLayer2, false);
	GetScrollBackdrop()->InsertLayer(pLayer1, idx1, Insert1);
	GetScrollBackdrop()->InsertLayer(pLayer2, idx2, Insert2);
}

math::Vec2 BackdropEditorScroll::GetOffset() const
{
	return ((BackdropScroll*)m_pBackdrop)->GetOffset();
}

void BackdropEditorScroll::RefreshAltText()
{
	bool bForeground;
	int Layer;

	if (GetCurrentLayer(&Layer, &bForeground))
	{
		if (BackdropLayer* pLayer = GetScrollBackdrop()->GetLayer(Layer, !bForeground))
		{
			char szText[256];
			std::string Name = pLayer->GetName();
			sprintf(szText, "\nCURRENT LAYER [%s:%d] PARALLAX SPEED [%5.2f] UVSCROLL [%s]",
					bForeground ? "foreground" : "background",
					Layer,
					pLayer->GetParallax(),
					pLayer->IsUVScroll() ? "yes" : "no");

			m_AltInstructions += szText;

			if (!Name.empty())
				m_AltInstructions += " (" + Name + ")";
		}
	}
}

void BackdropEditorScroll::EnableLayers(bool QuitEditor)
{
	if (AllowLayerEdit() && (m_CurrentLayer >= 0))
	{
		m_LayerHighlightInit = true;

		for (int i = 0; i < 2; i++)
		{
			bool bForeground = i ? true : false;
			unsigned int LayerC = GetScrollBackdrop()->GetLayerC(!bForeground);

			for (unsigned int layer = 0; layer < LayerC; layer++)
			{
				bool bEnabled = QuitEditor || (layer == ((m_CurrentLayer > MaxLayers()) ? (m_CurrentLayer - MaxLayers() - 1) : m_CurrentLayer));
				GetScrollBackdrop()->GetLayer(layer, !bForeground)->SetIsEnabled(bEnabled);
			}
		}
	}
}

void BackdropEditorScroll::RenderGridLines()
{
	Graphics::Vertex2D VertA[72];
	int Index = 0;
	Graphics* pG = GetGraphics();
	float x, y;
	float LineW = 0.5f / 800.0f;
	float LineH = 0.5f / 600.0f;
	math::Vec2 size = GetScrollBackdrop()->GetSize();
	math::Vec2 offset = GetOffset();
	math::Vec2 From, To;
	COLOR c;

	bool bAltLine = true;

	if (offset.x < 0.0f) offset.x += fabs(floor(offset.x));
	if (offset.y < 0.0f) offset.y += fabs(floor(offset.y));

	for (x = 0.0f; x <= size.x; x += 0.5f)
	{
		if (((x - offset.x) >= 0.0f) && ((x - offset.x) <= 1.0f))
		{
			From.x = To.x = x - offset.x;
			From.y = 0.0f;
			To.y = 1.0f;
			c = bAltLine ? 0x40FFFFFF : 0xAFFFFFFF;
			Index += GraphicsUtil::FillLine(From, To, LineW, c, c, &VertA[Index]);
		}
		
		bAltLine = !bAltLine;
	}

	bAltLine = true;

	for (y = 0.0f; y <= size.y; y += 0.5f)
	{
		if (((y - offset.y) >= 0.0f) && ((y - offset.y) <= 1.0f))
		{
			From.y = To.y = y - offset.y;
			From.x = 0.0f;
			To.x = 1.0f;
			c = bAltLine ? 0x40FFFFFF : 0xAFFFFFFF;
			Index += GraphicsUtil::FillLine(From, To, LineH, c, c, &VertA[Index]);
		}
		
		bAltLine = !bAltLine;
	}

	pG->SetTexture(0, NULL);
	pG->DrawVertex2D(VertA, Index);
}

}  //namespace backdrop
